﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Casamiel.Common;
using Casamiel.Common.Extensions;
using Casamiel.Domain.Entity;
using Casamiel.Domain;
using Casamiel.Domain.Response;
using Enyim.Caching;
using MediatR;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Casamiel.Application.Commands
{
    /// <summary>
    /// 
    /// </summary>
    public sealed class GetListCommandHandler : IRequestHandler<GetListCommand, BaseResult<List<StoreEntity>>>
    {
        private readonly IHttpClientFactory _clientFactory;
        private readonly IMbrStoreRepository _storeService;
        private readonly AMapConfig _aMapConfig;
		private readonly IMemcachedClient _memcachedClient;
		private readonly string _memcachedPre;
		public   GetListCommandHandler(IMbrStoreRepository mbrStoreRepository, IHttpClientFactory httpClientFactory, IOptionsSnapshot<AMapConfig> settings,
			IMemcachedClient memcachedClient, IOptionsSnapshot<CasamielSettings> snapshot)
        {
            if (settings is null)
            {
                throw new ArgumentNullException(nameof(settings));
            }

			if (snapshot is null) {
				throw new ArgumentNullException(nameof(snapshot));
			}

			_storeService = mbrStoreRepository;
            _clientFactory = httpClientFactory;
            _aMapConfig = settings.Value;
			_memcachedClient = memcachedClient;
			_memcachedPre = snapshot.Value.MemcachedPre;
        }
        public async Task<BaseResult<List<StoreEntity>>> Handle(GetListCommand request, CancellationToken cancellationToken)
        {
            if (request is null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var en = DistanceHelper.FindNeighPosition(request.Lng,request.Lat,request.Distance);
            
            if (request.Lat <= 0)
            {
                var storelist = await _storeService.GetStoreByName<ICasaMielSession>("", 1, int.MaxValue).ConfigureAwait(false);
                var list = storelist.Data;
                return new BaseResult<List<StoreEntity>>(list.Where(c=>c.IsCakeShopClose==0).ToList(), 0, "");
              //  return Ok(new { code = 0, content = list });
            }
            var list1 = await _storeService.GeRectRangeAsync<ICasaMielSession>(en.MinLat, en.MinLng, en.MaxLat, en.MaxLng).ConfigureAwait(false);
			list1 = list1.Where(c => c.IsCakeShopClose == 0).ToList();
			var _count = list1.Count;
            for (int i = 0; i < _count; i++)
            {
                list1[i].IsSend = false;
                list1[i].Distance = DistanceHelper.GetDistance(request.Lat, request.Lng, list1[i].Latitude, list1[i].Longitude);// _commonService.MapService.GetGistance(a, new Map { lat=item.Latitude.ToDouble(0), lng=item.Longitude.ToDouble(0)});
                var distributionRadius = $"{list1[i].DistributionRadius}".ToDouble(0);
                if (list1[i].Distance <= distributionRadius / 1000)
                {
                    if (list1[i].IsOpenSend > 0)
                    {
                        var _distance = await GetDistance(request.Lng, request.Lat, list1[i].Longitude, list1[i].Latitude).ConfigureAwait(false);
                        if (_distance <= distributionRadius)
                        {
                            list1[i].IsSend = true;
                        }
                    }
                }
            }
            //foreach (var item in list1)
            //{
            //    item.IsSend = false;
            //    item.Distance = DistanceHelper.GetDistance(request.Lat, request.Lng, item.Latitude, item.Longitude);// _commonService.MapService.GetGistance(a, new Map { lat=item.Latitude.ToDouble(0), lng=item.Longitude.ToDouble(0)});
            //    var distributionRadius = item.DistributionRadius.ToString().ToDouble(0);
            //    if (item.Distance <= distributionRadius/1000)
            //    {
            //        if (item.IsOpenSend > 0)
            //        {
            //            var _distance = await GetDistance(request.Lng, request.Lat, item.Longitude, item.Latitude);
            //            if (_distance <= distributionRadius)
            //            {
            //                item.IsSend = true;
            //            }
            //        }
            //    }
            //}

            var entity = list1.OrderBy(p => p.Distance).ToList();

            return new BaseResult<List<StoreEntity>>(entity, 0, "");
        }

        private async Task<double> GetDistance(double originLng,double originLat, double soriginLng, double soriginLat)
        {
			var cachekey = $"{_memcachedPre}Dist{originLng.ToString("#0.000000")}-{originLat.ToString("#0.000000")}-{soriginLng.ToString("#0.000000")}-{soriginLat.ToString("#0.000000")}";
			var ddd = await _memcachedClient.GetValueAsync<double>(cachekey).ConfigureAwait(false);
			if (ddd > 0) {
				return ddd;
			}
			var tUrl = $"{_aMapConfig.ApiUrl}/v4/direction/bicycling?origin={originLng},{originLat}&destination={soriginLng},{soriginLat}&key={_aMapConfig.ApiKey}";
            using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, tUrl))
            {
                using (var client = _clientFactory.CreateClient())
                {
                    using (var response = await client.SendAsync(requestMessage).ConfigureAwait(false))
                    {
                        if (response.IsSuccessStatusCode)
                        {
                            var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                            var json = JsonConvert.DeserializeObject<JObject>(result);
                            if (json["errcode"].ToString() == "0")
                            {
                                string distance = json["data"]["paths"][0]["distance"].ToString();
								await _memcachedClient.AddAsync(cachekey, distance.ToDouble(0), 7200).ConfigureAwait(false);
								return distance.ToDouble(0);
                            }
                        }
                    }
                }
                
                   
            }

             
            return 0;
        }
    }
}
